#include "dpidef.h"
#include "user_space.h"
#include "kernel_space.h"
#include "common.h"
#include "stdlib.h"
#include "stdio.h"
//#include "tlp.h"

#define FMT_3DWHND  0x00000000
#define FMT_4DWHND  0x20000000
#define FMT_3DWHWD  0x40000000
#define FMT_4DWHWD  0x60000000

#define TYPE_MRd      0x00000000
#define TYPE_MRdLk    0x01000000
#define TYPE_MWr      0x00000000
#define TYPE_IORd     0x02000000
#define TYPE_IOWr     0x02000000
#define TYPE_CfgRd0   0x04000000
#define TYPE_CfgWr0   0x04000000
#define TYPE_CfgRd1   0x05000000
#define TYPE_CfgWr1   0x05000000
#define TYPE_TCfgRd   0x1B000000
#define TYPE_TCfgWr   0x1B000000
#define TYPE_Msg      0x10000000
#define TYPE_MsgD     0x10000000
#define TYPE_Cpl      0x0A000000
#define TYPE_CplD     0x0A000000
#define TYPE_CplLk    0x0B000000
#define TYPE_CplDLk   0x0B000000
#define TYPE_FetchAdd 0x0C000000
#define TYPE_Swap     0x0D000000
#define TYPE_CAS      0x0E000000

unsigned short RequesterID;
unsigned char Tag;

int LoadPackets(FILE *file, unsigned int Dest, int Count)
{
  unsigned int PAddr, DAddr, Tail;
  unsigned int TagH, TagL;
  unsigned int *Buf;
  int i,j;
  int Bytes;
  char c;
  unsigned int Data;

  printf("LoadPackets %0x %d", Dest, Count);
  i = 0;
  DAddr = (unsigned int)Dest & 0xFFFFFFF0;
  Tail = 0;
  Buf = (unsigned int*) malloc(65536);
  while (!feof(file) && (i++ <Count))
  {
    if (fscanf(file, "%x %x %c", &TagH, &TagL, &c) != 3) break;
    for(j=0; j<1024; j++)
    {
      if(fscanf(file, "%x", &Data) != 1) 
        break;
      else
        Buf[j] = Data;
    }
    while(!feof(file) && (fgetc(file) != '\n'));
    if(j>0)
    {
      PAddr = DAddr + 16;
      Write((char*)PAddr, (char*)Buf, 4*j, &Bytes);
    
      Buf[0] = 0;
      Buf[1] = PAddr;
      Buf[2] = (TagL << 16) | 4*j;
      Buf[3] = TagH;
      Write((char*)DAddr, (char*)Buf, 16, &Bytes);
      if (Tail)
        MemWriteDW(Tail, DAddr);
      Tail = DAddr;
      DAddr = ((unsigned int)(PAddr + 4*j + 15)) & 0xFFFFFFF0;
    }
  }
  free(Buf);
  return i;
}

unsigned int StorePackets(FILE *file, unsigned int Src, int Count)
{
  unsigned int DAddr;
  unsigned int PAddr;
  unsigned int *Buf;
  int i,j;
  int Bytes;
  int Length;
  unsigned long long Tag;
  DAddr = Src;
  i = 0;
  Buf = (unsigned int*) malloc(65536);
  while (DAddr && (i++ < Count))
  {
    Read((char*)DAddr, (char*)Buf, 16, &Bytes);
    DAddr = Buf[0];
    PAddr = Buf[1];
    Length = Buf[2] & 0xFFFF;
    fprintf(file, "%08X %04X :", Buf[3], (Buf[2]>>16));
    Read((char*)PAddr, (char*)Buf, Length, &Bytes);
    for(j=0; j < Length/4; j++)
      fprintf(file, " 0x%08X", Buf[j]);
    fprintf(file, ";\n");
  }
  free(Buf);
  return i;
}

int DisplayPackets(unsigned int Src, int Count)
{
  unsigned int DAddr;
  unsigned int PAddr;
  unsigned int *Buf;
  int i,j;
  int Bytes;
  int Length;
  unsigned long long Tag;
  DAddr = Src;
  i = 0;
  Buf = (unsigned int*) malloc(65536);
  while (DAddr && (i++ < Count))
  {
    Read((char*)DAddr, (char*)Buf, 16, &Bytes);
    DAddr = Buf[0];
    PAddr = Buf[1];
    Length = Buf[2] & 0xFFFF;
    Tag = Buf[3];
    Tag = (Tag << 16) | (Buf[2] >> 16);
    Read((char*)PAddr, (char*)Buf, Length, &Bytes);
    printf("0x%016llx :", Tag);
    for(j=0; j <= Length/4; j++)
      printf(" 0x%08X", Buf[j]);
    printf("\n");
  }
  free(Buf);
  return i;
}

int ComparePackets(unsigned int ListA, unsigned int ListB, int Count)
{
  unsigned int A_DAddr;
  unsigned int B_DAddr;
  unsigned int A_PAddr;
  unsigned int B_PAddr;
  unsigned int *A_Buf;
  unsigned int *B_Buf;
  int A_Length;
  int B_Length;
  int Bytes;
  int i, j;
  
  i = 0;
  A_Buf = (unsigned int*) malloc(65536);
  B_Buf = (unsigned int*) malloc(65536);
  A_DAddr = ListA;
  B_DAddr = ListB;
  while (A_DAddr && B_DAddr && (i < Count))
  {
    Read((char*)A_DAddr, (char*)A_Buf, 16, &Bytes);
    A_DAddr = A_Buf[0];
    A_PAddr = A_Buf[1];
    A_Length = A_Buf[2] & 0xFFFF;
    Read((char*)B_DAddr, (char*)B_Buf, 16, &Bytes);
    B_DAddr = B_Buf[0];
    B_PAddr = B_Buf[1];
    B_Length = B_Buf[2] & 0xFFFF;
    if (A_Length != B_Length)
      break;

    Read((char*)A_PAddr, (char*)A_Buf, A_Length, &Bytes);
    Read((char*)B_PAddr, (char*)B_Buf, B_Length, &Bytes);
    for(j=0; j<A_Length/4; j++)
    {
      if(A_Buf[j] != B_Buf[j])
        break;
    }
    if (j != A_Length/4)
      break;
    i++;
  }
  
  free(A_Buf);
  free(B_Buf);
  
  return i;
}

void PostProcess(unsigned int *ppDescriptor)
{
  unsigned int ListHead;
  unsigned int NewListHead;
  int NextNode;
  ListHead = (unsigned int) *ppDescriptor;
  NewListHead = 0;
  while(ListHead)
  {
    MemReadDW(ListHead, &NextNode);
    MemWriteDW(ListHead, NewListHead);
    NewListHead = ListHead;
    ListHead = NextNode;
  }
  *ppDescriptor = NewListHead;
}

int AnStartCapture(unsigned int StartPage, unsigned int EndPage)
{
  RegWriteDWord(0x100A0004, StartPage);
  RegWriteDWord(0x100A000C, EndPage);
  RegWriteByte(0x100A0020, 0x1);
  RegWriteByte(0x100A0000, 0x1);
  return 0;
}
int AnStopCapture()
{
  unsigned int Val;
  RegWriteByte(0x100A0020, 0x2);
  //Wait for the fifo to be empty
  do
  {
    RegReadDWord(0x100A0020, &Val);
    Val = Val & 0x00040000;
  } while(!Val);
  RegWriteByte(0x100A0000, 0x0);
  do
  {
    RegReadDWord(0x100A0000, &Val);
    Val = (Val & 0x000F0000) >> 16;
  }while(Val !=0);
  return 0;
}
int ExStartRecording(unsigned int StartPage, unsigned int EndPage)
{
  RegWriteDWord(0x100B0004, StartPage);
  RegWriteDWord(0x100B000C, EndPage);
  RegWriteByte(0x100B0000, 0x1);
  return 0;
}

int ExStopRecording()
{
  unsigned int State;
  RegWriteDWord(0x100B0000, 0x0);
  do
  {
    RegReadDWord(0x100B0000, &State);
    State = (State & 0x000F0000) >> 16;
  }while(State !=0);
  return 0;
}

int ExStartPlaying(unsigned int Descriptor)
{
  RegWriteDWord(0x100B0024, Descriptor);
  RegWriteByte(0x100B0020, 0x1);
  return 0;
}

int ExStopPlaying()
{
  unsigned int State;
  RegWriteDWord(0x100B0020, 0x0);  //Disable Player
  do
  {
    RegReadDWord(0x100B0020, &State);
    State = (State & 0x000F0000) >> 16;
  } while(State != 0x0);
  return 0;
}

unsigned int ExGetPacketsTransmitted()
{
  unsigned int Count;
  RegReadDWord(0x100B0034, &Count);
  return Count;
}

unsigned int ExGetPacketsReceived()
{
  unsigned int Count;
  RegReadDWord(0x100B0014, &Count);
  return Count;
}

int user_main()
{
  int BytesRead;
  FILE *ofile;
  FILE *ifile;
  unsigned int pDescriptor = 0x70002FD0;
  int State;  
  int i;
  unsigned int Count;
  
  printf("Begin main()\n");

  printf("Loading packets from File\n");
  ifile = fopen("input.txt", "r");
  LoadPackets(ifile, pDescriptor, 100);
  fclose(ifile);

  printf("Setting Up Analyzer\n");
  AnStartCapture(0x7000E000, 0x7000F000);
  ExStartRecording(0x70000000, 0x70001000);
  ExStartPlaying(pDescriptor);
  while(ExGetPacketsTransmitted() != 10);
  ExStopPlaying();
  ExStartPlaying(pDescriptor);
  while(ExGetPacketsTransmitted() != 10);
  ExStopPlaying();  
  ExStartPlaying(pDescriptor);
  while(ExGetPacketsTransmitted() != 10);
  ExStopPlaying();  
  ExStopRecording();
  AnStopCapture();

  RegReadDWord(0x100B0008, (int*)&pDescriptor);
  
  PostProcess(&pDescriptor);
  
  ofile = fopen("output.txt", "w");
  StorePackets(ofile, pDescriptor, 100);
  fclose(ofile);

  i = ComparePackets(0x2FD0, pDescriptor, 100);
  printf("comparision Result = %d\n", i);
  
  printf("Packets Transmitted %d\n", ExGetPacketsTransmitted());
  printf("Packets Received %d\n", ExGetPacketsReceived());
  
  printf("End main()\n");
  return 0;
}
